package com.ruanxie.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ruanxie.context.BaseContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruanxie.dto.QueryModel;
import com.ruanxie.dto.student.StudentGetCourseGradeDTO;
import com.ruanxie.dto.student.StudentHuebImportDTO;
import com.ruanxie.entity.*;
import com.ruanxie.json.jsonconverter.*;
import com.ruanxie.mapper.StudentMapper;
import com.ruanxie.result.PageResult;
import com.ruanxie.service.StudentService;
import com.ruanxie.utils.HuebUtil;
import com.ruanxie.vo.student.MajorTeachingPlanInfoVO;
import com.ruanxie.vo.student.StudentCourseGradeVO;
import com.ruanxie.vo.student.TeachingPlanCourseInfoVO;
import com.ruanxie.vo.student.StudentGetCourseScheduleOfStudentVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service//这个别忘了，声明是业务层，同时变为组件
@Slf4j
public class StudentServiceImpl implements StudentService {

    @Autowired
    private HuebUtil huebUtil;
    @Autowired
    private StudentMapper studentMapper;
    /**
     * 获取到河北经贸大学的验证码
     * @return
     */
    @Override
    public String getHuebCaptcha() {
        String captcha=huebUtil.getCaptcha();
        return captcha;
    }

    /**
     * 获取到河北经贸大学当前登录的cookie
     * @return
     */
    @Override
    public String getHuebCookie(StudentHuebImportDTO studentHuebImportDTO) {
        String huebCookie = huebUtil.getCookies(studentHuebImportDTO.getAccountId(), studentHuebImportDTO.getPassword(), studentHuebImportDTO.getCaptcha());

        return huebCookie;
    }


    /**
     * 通过cookie，发起各种网络请求，获取到官网中的各种数据
     * @param huebCookie
     */
    @Override
    public void huebImportAllData(String huebCookie) throws IOException {
        //导入学生的基本信息
        HuebStudentJsonConverter huebStudentJsonConverter=huebImportStudentData(huebCookie);

        //导入专业的教学执行计划
//        HuebTeachingPlanInfoJsonConverter huebTeachingPlanInfoJsonConverter=huebImportTeachingPlanInfoData(huebCookie,huebStudentJsonConverter.getYearOfEntry(),huebStudentJsonConverter.getMajorId());
//        huebImportAllMajorCourceAndPlan(huebCookie,huebTeachingPlanInfoJsonConverter.getTeachingPlanInfoId());
            //将上面操作合并为事务
        TeachingPlanInfo teachingPlanInfo=studentMapper.getTeachingPlanInfoByMajorNameAndYearOfentry(huebStudentJsonConverter.getMajorName(),huebStudentJsonConverter.getYearOfEntry());
                                        //小小注意下：数据库中用的都是专业名称
//        log.info("当前专业对应的教学执行计划：{}",teachingPlanInfo);
        if(teachingPlanInfo==null){
            log.info("导入专业的教学执行计划信息...");
            huebImportMajorAllTeachingPlan(huebCookie,huebStudentJsonConverter.getYearOfEntry(),huebStudentJsonConverter.getMajorId());
        }

        //导入学生当前学年的课表信息
        huebImportCourseScheduleOfStudent(huebCookie);

        //导入学生所有的成绩信息
        huebImportCourseGradeOfStudent(huebCookie,null,null);
            //TODO 可以优化：更新完一次后，只请求当前学年
            //      这里只要不是很有必要，影响不是特别大
    }

    /**
     * 导入学上基本信息
     *
     * @param huebCookie
     * @return
     */
    @Override
    public HuebStudentJsonConverter huebImportStudentData(String huebCookie) throws IOException {
        log.info("正在导入学生数据...");
        //获取学生的json数据
        HuebStudentJsonConverter huebStudentJsonConverter= null;
        huebStudentJsonConverter = huebUtil.getHuebStudentJsonConverter(huebCookie);
        //转化为数据库对应的实体类
        log.info("获取到的学生信息:{}",huebStudentJsonConverter);
        Student student=new Student();
        BeanUtils.copyProperties(huebStudentJsonConverter,student);

        //完成：将student(学生信息)保存到数据库中
        studentMapper.saveStudent(student);

        //TODO 参考：有重复数据：https://segmentfault.com/a/1190000039912996


        return huebStudentJsonConverter;
    }

    /**
     * 导入学生的教学执行计划专业的信息
     * @param huebCookie
     * @param yearOfEntry
     * @param majorId
     * @return
     */
    @Override
    public HuebTeachingPlanInfoJsonConverter huebImportTeachingPlanInfoData(String huebCookie, String yearOfEntry, String majorId) throws IOException {
        log.info("正在导入专业的教学执行计划...");
        //从河北经贸大学获取到教学执行计划的专业信息
        HuebTeachingPlanInfoJsonConverter huebTeachingPlanInfoJsonConverter=huebUtil.getHuebTeachingPlanInfoJsonConverter(huebCookie,yearOfEntry,majorId);
        //转化为数据库对应的实体类
        log.info("获取到教学执行计划的专业信息:{}",huebTeachingPlanInfoJsonConverter);
        TeachingPlanInfo teachingPlanInfo=new TeachingPlanInfo();
        BeanUtils.copyProperties(huebTeachingPlanInfoJsonConverter,teachingPlanInfo);
        //保存进数据库中
        studentMapper.saveTeachingPlanInfo(teachingPlanInfo);
        return huebTeachingPlanInfoJsonConverter;
    }

    /**
     * 导入专业的教学执行计划所有的课程信息和计划(必修+限选)
     * (这里直接就一起导入了)
     *
     * @param huebCookie
     * @param teachingPlanInfoId
     */
    @Override
    public void huebImportAllMajorCourceAndPlan(String huebCookie, String teachingPlanInfoId) throws IOException {
        log.info("正在导入教学执行计划{}的课程信息...",teachingPlanInfoId);
        //获取到河北经贸大学中专业对应的教学执行计划的完整课程信息（包括部分课程信息和教学执行计划课程信息）
        List<HuebTeachingPlanCourseInfoJsonConverter> teachingPlanCourseInfoJsonConverterList=huebUtil.getHuebTeachingPlanCourseInfoJsonConverterList(huebCookie,teachingPlanInfoId);
//        log.info("教学执行计划课程信息：{}",teachingPlanCourseInfoJsonConverterList);


        //因为这个多表查询，这里想着牺牲一点效率映射为数据库对应的实体类
            // 用于存储 Course 实体类的列表
        List<Course> courseList = new ArrayList<>();
            // 用于存储 TeachingPlanCourseInfo 实体类的列表
        List<TeachingPlanCourseInfo> teachingPlanCourseInfoList = new ArrayList<>();

        for(HuebTeachingPlanCourseInfoJsonConverter huebTeachingPlanCourseInfoJsonConverter:teachingPlanCourseInfoJsonConverterList){
            Course course=new Course();
            BeanUtils.copyProperties(huebTeachingPlanCourseInfoJsonConverter,course);
            courseList.add(course);

            // 将 jsonConverter 的属性复制到 TeachingPlanCourseInfo 实体类
            TeachingPlanCourseInfo teachingPlanCourseInfo = new TeachingPlanCourseInfo();
            BeanUtils.copyProperties(huebTeachingPlanCourseInfoJsonConverter, teachingPlanCourseInfo);
            teachingPlanCourseInfoList.add(teachingPlanCourseInfo);
        }

        //将这些列表存到数据库中
        studentMapper.saveCourseList(courseList);
        studentMapper.saveTeachingPlanCourseInfoList(teachingPlanCourseInfoList);
    }

    /**
     * 导入专业的教学执行计划的所有信息
     * (huebImportTeachingPlanInfoData和huebImportAllMajorCourceAndPlan和在一起，
     *  并使用业务来维护，把传播行为属性定义为总是新建（避免事务间相互影响），进一步避免重复导入)
     * @param huebCookie
     * @param yearOfEntry
     * @param majorId
     * @throws IOException
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
        //默认情况下，只有只有出现RuntimeException(运行时异常)才会回滚事务，所以设置了rollbackFor
    @Override
    public void huebImportMajorAllTeachingPlan(String huebCookie, String yearOfEntry, String majorId) throws IOException {
        HuebTeachingPlanInfoJsonConverter huebTeachingPlanInfoJsonConverter=huebImportTeachingPlanInfoData(huebCookie,yearOfEntry,majorId);
        huebImportAllMajorCourceAndPlan(huebCookie,huebTeachingPlanInfoJsonConverter.getTeachingPlanInfoId());
    }

    /**
     * 导入学生当前学年当前学期对应的课表
     * @param huebCookie
     */
    @Override
    public void huebImportCourseScheduleOfStudent(String huebCookie) throws IOException {
        //获取到对应课表数据
        HuebCourseScheduleOfStudentJsonConvert huebCourseScheduleOfStudentJsonConvert = huebUtil.getHuebCourseScheduleOfStudentJsonConvert(huebCookie);

        //将课表数据转化为json格式
        // 这个bug没有解决：这里又用Jackson的原因是因为，fastjson序列化时，没办法忽视@JSONField注解，还是会按这个序列化，而不是按原来的属性名
//        String courseScheduleJson = JSON.toJSONString(huebCourseScheduleOfStudentJsonConvert, SerializerFeature.WriteNonStringKeyAsString);
//                    //设置完第二个参数：`fastjson 会使用类中的属性名而不是 @JSONField 注解中的名字。
//        System.out.println(courseScheduleJson);
        ObjectMapper objectMapper = new ObjectMapper();
        String courseScheduleJson = objectMapper.writeValueAsString(huebCourseScheduleOfStudentJsonConvert);

        //存入数据库中
        String studentId = BaseContext.getCurrentId();//必须学生端才能使用这个
        studentMapper.saveCourseScheduleOfStudent(studentId,courseScheduleJson);
    }

    /**
     * 导入学生当前的成绩信息
     * @param huebCookie
     */
    @Override
    public void huebImportCourseGradeOfStudent(String huebCookie,String schoolYear, String term) throws IOException {

        //获取到当前的课表
        List<HuebCourseGradeOfStudentJsonConvert> huebCourseGradeOfStudentJsonConvertList = huebUtil.getHuebCourseGradeOfStudentJsonConvertList(huebCookie,null,null);

        // 用于存储 TeachingClass 实体类的列表
        List<TeachingClass> teachingClassList = new ArrayList<>();
        // 用于存储 Enrollment 实体类的列表
        List<Enrollment> enrollmentList = new ArrayList<>();
        // 用于存储 Course 实体类的列表
        List<Course> courseList = new ArrayList<>();

        //将河北经贸大学的成绩信息转存到数据库中
        for (HuebCourseGradeOfStudentJsonConvert huebCourseScheduleOfStudentJsonConvert:huebCourseGradeOfStudentJsonConvertList){
            // 创建并设置 TeachingClass 实体类对象
            TeachingClass teachingClass = new TeachingClass();
            BeanUtils.copyProperties(huebCourseScheduleOfStudentJsonConvert,teachingClass);
            teachingClassList.add(teachingClass);

            // 创建并设置 Enrollment 实体类对象
            Enrollment enrollment = new Enrollment();
            BeanUtils.copyProperties(huebCourseScheduleOfStudentJsonConvert,enrollment);
            enrollmentList.add(enrollment);

            //课程
            Course course = new Course();
            BeanUtils.copyProperties(huebCourseScheduleOfStudentJsonConvert,course);
            courseList.add(course);
        }

        // 将列表存到数据库中
        studentMapper.saveTeachingClassList(teachingClassList);
        studentMapper.saveEnrollmentList(enrollmentList);
        studentMapper.saveCourseList(courseList);

    }


    /**
     * 插入学生信息
     * @param student
     */
    @Override
    public void save(Student student) {
        studentMapper.saveStudent(student);
    }

    /**
     * 插入教学执行计划课程信息
     * @param teachingPlanCourseInfo
     */
    @Override
    public void save(TeachingPlanCourseInfo teachingPlanCourseInfo) {
        studentMapper.saveTeachingPlanCourseInfo(teachingPlanCourseInfo);
    }

    /**
     * 插入教学执行计划信息
     * @param teachingPlanInfo
     */
    @Override
    public void save(TeachingPlanInfo teachingPlanInfo) {
        studentMapper.saveTeachingPlanInfo(teachingPlanInfo);
    }



    /**
     * 导入学生课程信息测试
     * @param studentId
     * @param courseSchedule
     * @return
     */
    @Override
    public void save(String studentId,String courseSchedule) {
        studentMapper.saveCourseScheduleOfStudent(studentId,courseSchedule);
    }


//    /**
//     * json数据存取测试
//     * @param jsonString
//     */
//    @Override
//    public void save(String jsonString) {
//        studentMapper.saveJson(jsonString);
//    }

    /**
     * 查询学生课程信息测试
     * @return
     */
    @Override
    public CourseScheduleOfStudent selectCourseScheduleOfStudent() {
        return studentMapper.getCourseScheduleOfStudent("1");
    }

    /**
     * 查询当前学年当前学期的学生课表
     * @return
     */
    @Override
    public StudentGetCourseScheduleOfStudentVO getStudentGetCourseScheduleOfStudentVO() {
        String studentId=BaseContext.getCurrentId();
        CourseScheduleOfStudent courseScheduleOfStudent=studentMapper.getCourseScheduleOfStudent(studentId);
        //这里感觉复制有点冗余了
        StudentGetCourseScheduleOfStudentVO studentGetCourseScheduleOfStudentVO=new StudentGetCourseScheduleOfStudentVO(studentId,courseScheduleOfStudent.getCourseSchedule());
        return studentGetCourseScheduleOfStudentVO;
    }

    /**
     * 查询课程成绩
     * @param studentGetCourseGradeDTO
     * @return
     */
    @Override
    public PageResult getCourseGrade(StudentGetCourseGradeDTO studentGetCourseGradeDTO) {
        QueryModel queryModel=studentGetCourseGradeDTO.getQueryModel();
        //分页查询设置
        PageHelper.startPage(queryModel.getPageNum(),queryModel.getPageSize(),queryModel.getSortOrder());
        //设置查询成绩的条件
        String studentId=BaseContext.getCurrentId();
        String schoolYear=studentGetCourseGradeDTO.getSchoolYear();
        String term = studentGetCourseGradeDTO.getTerm();
        String courseNature = studentGetCourseGradeDTO.getCourseNature();
        Page<StudentCourseGradeVO> page =  studentMapper.getCourseGradeOfStudent(studentId, schoolYear, term, courseNature);
        //获取查询结果
        long total=page.getTotal();
        List<StudentCourseGradeVO> studentCourseGradeVOList=page.getResult();
        return new PageResult(total,studentCourseGradeVOList);
    }

    /**
     * 查询专业教学执行计划
     * @return
     */
    @Override
    public MajorTeachingPlanInfoVO getMajorTeachingPlanInfo() {
        String studentId=BaseContext.getCurrentId();
        log.info(studentId);
        TeachingPlanInfo teachingPlanInfo=studentMapper.getTeachingPlanInfoByStudentId(studentId);

        List<TeachingPlanCourseInfoVO> teachingPlanCourseInfoVOList=studentMapper.getTeachingPlanCourseInfoVOByTeachingPlanInfoId(teachingPlanInfo.getTeachingPlanInfoId());

        MajorTeachingPlanInfoVO majorTeachingPlanInfoVO=new MajorTeachingPlanInfoVO();

        BeanUtils.copyProperties(teachingPlanInfo,majorTeachingPlanInfoVO);
        majorTeachingPlanInfoVO.setTeachingPlanCourseInfoVO(teachingPlanCourseInfoVOList);
        return majorTeachingPlanInfoVO;
    }

    /**
     * 插入课程信息
     * @param course
     */
    @Override
    public void save(Course course) {
        studentMapper.saveCourse(course);
    }

}
